package com.example.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @ClassName LockService
 * @Description
 * @Author Jingxiao.Ye
 * @Date 2022/1/20 上午12:08
 * @Version V1.0
 * @Since JDK 11
 */
@Service
public class LockService {

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    private String lockLua = "--锁的名称\n" +
            "local lockName=KEYS[1]\n" +
            "--锁的value\n" +
            "local lockValue=ARGV[1]\n" +
            "--过期时间 秒\n" +
            "local timeout=tonumber(ARGV[2],10)\n" +
            "--尝试进行加锁\n" +
            "local flag=redis.call('setnx', lockName, lockValue)\n" +
            "--判断是否获得锁\n" +
            "if flag == 1 then\n" +
            "--获得分布式锁，设置过期时间\n" +
            "redis.call('expire', lockName, timeout)\n" +
            "end\n" +
            "--返回标识\n" +
            "return flag ";

    private String unLockLua = "--锁的名称\n" +
            "local lockName=KEYS[1]\n" +
            "--锁的value\n" +
            "local lockValue=ARGV[1]\n" +
            "--判断锁是否存在，以及锁的内容是否为自己加的\n" +
            "local value=redis.call('get', lockName)\n" +
            "--判断是否相同\n" +
            "if value == lockValue then\n" +
            "     redis.call('del', lockName)\n" +
            "     return 1\n" +
            "end\n" +
            "return 0";

    public String lock(String lockName,int timeout){

        String token = UUID.randomUUID().toString();
        //设置给threadLocal

        //分布式锁 - 加锁
        Long flag = redisTemplate.execute(new DefaultRedisScript<>(lockLua, Long.class),
                Collections.singletonList(lockName),
                token, timeout
        );

        System.out.println("获得锁的结果：" + flag);

        if (flag == 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }
        return token;
    }

    public void unlock(String lockName,String token){
        redisTemplate.execute(new DefaultRedisScript<>(unLockLua, Long.class),
                Collections.singletonList(lockName),
                token
        );
    }
}
